﻿#pragma once

#include <learn/geom/vec.h>
#include <learn/topo/half_mesh.h>

namespace xi
{

namespace mesh
{

using namespace xi::geom;
using namespace xi::topo;

template <std::size_t N> class EXT_SYMBOL Mesh3D
{
};

template <> class EXT_SYMBOL Mesh3D<3> : public Half_Triangle_Mesh
{
  protected:
    VProperty_Handle<std::size_t> m_vertexId;
    VProperty_Handle<Vec3f> m_vertexPos;
    VProperty_Handle<Vec3f> m_vertexNormal;
    VProperty_Handle<Vec2f> m_vertexTexcoord;
    FProperty_Handle<Vec3f> m_faceNormal;

  public:
    /**
     * @brief 默认构造函数.
     *
     */
    Mesh3D();

    /**
     * @brief 删除所有赋值和拷贝构造函数
     *
     */
    Mesh3D(Mesh3D &&) = delete;

    /**
     * @brief 析构函数
     *
     */
    virtual ~Mesh3D() = default;

    /**
     * @brief 获得顶点 ID
     *
     * @param[in] v
     * @return std::size_t
     */
    std::size_t vertex_id(VHandle v) const;

    /**
     * @brief 获得顶点 ID
     *
     * @param[in] v
     * @return std::size_t&
     */
    std::size_t &vertex_id(VHandle v);

    /**
     * @brief 获得顶点位置
     *
     * @param[in] v
     * @return Vec3f
     */
    Vec3f vertex_pos(VHandle v) const;

    /**
     * @brief 获得顶点位置
     *
     * @param[in] v
     * @return Vec3f&
     */
    Vec3f &vertex_pos(VHandle v);

    /**
     * @brief 获得顶点法向
     *
     * @param[in] v
     * @return Vec3f
     */
    Vec3f vertex_normal(VHandle v) const;

    /**
     * @brief 获得顶点法向
     *
     * @param[in] v
     * @return Vec3f&
     */
    Vec3f &vertex_normal(VHandle v);

    /**
     * @brief 获得顶点纹理坐标
     *
     * @param[in] v
     * @return Vec2f
     */
    Vec2f vertex_texcoord(VHandle v) const;

    /**
     * @brief 获得顶点纹理坐标
     *
     * @param[in] v
     * @return Vec2f&
     */
    Vec2f &vertex_texcoord(VHandle v);

    /**
     * @brief 获得面法向
     *
     * @param[in] f
     * @return Vec3f
     */
    Vec3f face_normal(FHandle f) const;

    /**
     * @brief 获得面法向
     *
     * @param[in] f
     * @return Vec3f&
     */
    Vec3f &face_normal(FHandle f);

    /**
     * @brief 构造顶点
     *
     * @param[in] pos
     * @return vertex__Handle
     */
    VHandle create_vertex(const Vec3f &pos);

    /**
     * @brief 从顶点创建面
     *
     * @param[in] v0
     * @param[in] v1
     * @param[in] v2
     * @return FHandle
     */
    FHandle create_face(VHandle v0, VHandle v1, VHandle v2);

    /**
     * @brief 从边创建面
     *
     * @param[in] c0
     * @param[in] c1
     * @param[in] c2
     * @return FHandle
     */
    FHandle create_face(CHandle c0, CHandle c1, CHandle c2);

    /**
     * @brief 要求面法向.
     * @see
     */
    void request_face_normals();

    /**
     * @brief 移除面法向.
     * @see
     */
    void remove_face_normals();

    /**
     * @brief 要求顶点法向
     * @see
     */
    void request_vertex_normals();

    /**
     * @brief 移除顶点法向.
     * @see
     */
    void remove_vertex_normals();

    /**
     * @brief 创建顶点纹理坐标.
     * @see
     */
    void request_vertex_texcoords();

    /**
     * @brief 移除顶点纹理坐标.
     * @see
     */
    void remove_vertex_texcoords();

    /**
     * @brief 创建顶点 ID.
     *
     */
    void request_vertex_ids();

    /**
     * @brief 移除顶点 ID.
     *
     */
    void remove_vertex_ids();

    /**
     * @brief 计算面法向
     *
     */
    void update_face_normals();

    /**
     * @brief 计算顶点法向 Gouraud 插值
     *
     */
    void update_vertex_normals();
};

} // namespace mesh

} // namespace xi
